<template>
  <section class="nui-scroll nui-scroll-x">
    <Toast />
    {renderPanelBody()}
  </section>
</template>

<script>
  import { ref, watch, computed } from 'vue';
  import tools from '../tools/index';
  import MyInput from './input';
  import event from '../tools/event';
  import fnModules from '../tools/fns';
  import Toast from './toast';

  export default {
    name: 'mutilTable',
    props: {
      tableData: {
        type: Array,
        default: () => [],
      },
      tableHeader: {
        type: Array,
        default: () => [],
      },
      bodyNotShowProps: {
        type: Array,
        default: () => [],
      },
      tableBorderColor: {
        type: String,
        default: '#ddd',
      },
      cellHeight: {
        type: Number,
        default: 40,
      },
      uniqueKey: {
        type: String,
        default: '',
      },
      firstThClickHandler: {
        type: Function,
        default: () => null,
      },
      isFirstThEableClick: {
        type: Boolean,
        default: false,
      },
      firstThStyle: {
        type: Object,
        default: () => ({}),
      },
      isReadOnly: {
        type: Boolean,
        default: false,
      },
      bodyEmptyTips: {
        type: String,
        default: '暂无数据',
      },
      headerStyle: {
        type: Object,
        default: () => ({
          background: 'rgb(230, 242, 246)',
          color: '#333',
        }),
      },
      cellStyle: {
        type: Object,
        default: () => ({
          background: '#fff',
          color: '#333',
        }),
      },
      calcCellStyle: {
        type: Object,
        default: () => ({
          background: '#999',
          color: '#fff',
        }),
      },
    },
    components: {
      Toast,
    },
    setup(props) {
      const ossTableHeader = ref([]);
      const ossTableData = ref([]);
      const headerArr = ref([]);
      const bodyNotShowPropData = ref([]);
      const curTableData = ref([]);
      const curEditTdId = ref('');
      const isBodyEmpty = ref(false);

      // 表头层级
      const headerClasses = computed(() => {
        const arr = headerArr.value.map((item) => item.classifyId);
        return [...new Set(arr)];
      });

      const initData = () => {
        headerArr.value = [];
        ossTableData.value = tools.deepCopy(props.tableData);
        ossTableHeader.value = tools.deepCopy(props.tableHeader);
        curTableData.value = tools.deepCopy(props.tableData);
        bodyNotShowPropData.value = [
          ...new Set([...tools.deepCopy(props.bodyNotShowProps), 'table_id']),
        ];

        ossTableData.value.forEach((item) => {
          if (!props.uniqueKey) {
            if (!item.table_id) {
              item.table_id = tools.guid();
            }
          } else {
            item.table_id = item[props.uniqueKey] ? item[props.uniqueKey] : tools.guid();
          }
        });

        if (ossTableData.value.length) {
          for (const [k, v] of Object.entries(ossTableData.value[0])) {
            if (typeof v === 'object') {
              combineCellByKey(k);
            }
          }
          isBodyEmpty.value = false;
        } else {
          isBodyEmpty.value = true;
        }

        ossTableHeader.value = giveIdx2Item(ossTableHeader.value);
        getHeaderItemArr(ossTableHeader.value);
      };

      const combineCellByKey = (key) => {
        const arr = [];
        ossTableData.value.forEach((item) => {
          const _idx = arr.findIndex((_) => tools.checkIfObjectEqual(_, item[key]));
          if (_idx === -1) {
            arr.push(item[key]);
          } else {
            delete item[key];
          }
        });
      };

      const classifyHeaderHandler = () => {
        const common = {
          verticalAlign: 'middle',
          borderRight: `1px solid ${props.tableBorderColor}`,
        };

        return (
          <thead>
            {headerClasses.value.map((val) => {
              return (
                <tr
                  style={{
                    ...props.headerStyle,
                    borderTop: `1px solid ${props.tableBorderColor}`,
                  }}
                >
                  {headerArr.value
                    .filter((item) => item.classifyId === val)
                    .filter((item) => item.title)
                    .map((item, _idx) => {
                      return (
                        <th
                          rowspan={getRowspan(item)}
                          colspan={item.colSpan ? item.colSpan : 1}
                          style={
                            _idx === 0 &&
                            props.isFirstThEableClick &&
                            item.sortIdx === '0' &&
                            item.classifyId === 0
                              ? {
                                  ...common,
                                  ...props.firstThStyle,
                                  cursor: 'pointer',
                                  height: `${props.cellHeight * getRowspan(item)}px`,
                                }
                              : {
                                  ...common,
                                  height: `${props.cellHeight * getRowspan(item)}px`,
                                }
                          }
                          onClick={() => {
                            if (
                              !props.isFirstThEableClick ||
                              _idx !== 0 ||
                              item.sortIdx !== '0' ||
                              item.classifyId !== 0
                            ) {
                              return;
                            }
                            // 点击第一个th单元格触发事件
                            props.firstThClickHandler();
                          }}
                        >
                          <span>{item.title}</span>
                        </th>
                      );
                    })}
                </tr>
              );
            })}
          </thead>
        );
      };

      const tdClickHandler = (tableId, isCanEdit) => {
        if (!isCanEdit) {
          return;
        }

        curEditTdId.value = tableId;
      };

      const renderPanelBody = () => {
        // body无数据
        const emptyBody = () => {
          return (
            <div
              class="flexBox"
              style={{
                height: '100px',
                border: `1px solid ${props.tableBorderColor}`,
              }}
            >
              {props.bodyEmptyTips}
            </div>
          );
        };

        // body有数据
        const renderBody = () => {
          return (
            <tbody
              style={{
                width: '100%',
                borderTop: `1px solid ${props.tableBorderColor}`,
              }}
            >
              {ossTableData.value.map((item) => renderTableColumn(item))}
            </tbody>
          );
        };

        return (
          <div>
            <table
              cellspacing="0"
              cellpadding="0"
              style={{
                width: '100%',
                borderLeft: `1px solid ${props.tableBorderColor}`,
                borderRight: `1px solid ${props.tableBorderColor}`,
              }}
            >
              {classifyHeaderHandler()}
              {isBodyEmpty.value === false ? renderBody() : null}
            </table>
            {isBodyEmpty.value === false ? null : emptyBody()}
          </div>
        );
      };

      const getHeaderItemSortIndex = (target_key) => {
        const _idx = headerArr.value.findIndex((item) => item.key === target_key);
        if (_idx === -1) {
          return '';
        }
        return headerArr.value[_idx].sortIdx;
      };

      const getHeaderItemArr = (arr1) => {
        const bianli = (arr) => {
          arr.map((item) => {
            if (item.children && item.children.length) {
              const idx = headerArr.value.findIndex(
                (_) => _.title === item.title && _.sortIdx === item.sortIdx,
              );
              if (idx === -1) {
                const _temp = tools.deepCopy(item);
                delete _temp.children;
                headerArr.value.push(_temp);
              }
              bianli(Reflect.get(item, 'children'));
            } else {
              const _idx = headerArr.value.findIndex((_) => _.key === item.key);
              if (_idx === -1) {
                headerArr.value.push(item);
              }
            }
          });
        };
        bianli(arr1);
      };

      const getRowspan = (cell) => {
        return cell.rowSpan ? cell.rowSpan : 1;
      };

      const getIfHeaderItemCanEditByKey = (key) => {
        const _idx = headerArr.value.findIndex((item) => item.key === key);
        if (_idx === -1) {
          return false;
        }
        return headerArr.value[_idx].isCanEdit;
      };

      const isAfrontB = (A, B) => {
        if (!A || !B) {
          return 0;
        }
        const A_arr = A.split('_').map((item) => Number(item));
        const B_arr = B.split('_').map((item) => Number(item));
        const len = Math.min(...[A_arr.length, B_arr.length]);
        for (let i = 0; i < len; i++) {
          if (A_arr[i] - B_arr[i] > 0) {
            return 1;
          } else if (A_arr[i] - B_arr[i] < 0) {
            return -1;
          }
        }
        return 0;
      };

      const renderTableColumn = (colOptions) => {
        const sortArr = Object.keys(colOptions)
          .filter((item) => !bodyNotShowPropData.value.includes(item))
          .sort((a, b) => {
            const flag = isAfrontB(getHeaderItemSortIndex(a), getHeaderItemSortIndex(b));
            return flag;
          });

        return (
          <tr style={{ ...props.cellStyle, width: '100%' }}>
            {sortArr.map((item, idx) => {
              const common = {
                padding: '0 25px',
                minWidth: '100px',
                height: `${
                  props.cellHeight *
                  (typeof colOptions[item] === 'object' ? colOptions[item].rowSpan : 1)
                }px`,
              };

              const isReadOnlySpan = (() => {
                const common = {
                  ...props.cellStyle,
                  minWidth: '120px',
                  borderTop: 'none',
                  borderBottom: 'none',
                  borderRight: 'none',
                  borderRadius: 0,
                  textAlign: 'center',
                  height:
                    props.cellHeight *
                      (typeof colOptions[item] === 'object'
                        ? colOptions[item].rowSpan
                          ? colOptions[item].rowSpan
                          : 1
                        : 1) +
                    'px',
                };
                return (
                  <MyInput
                    addStyle={
                      colOptions[item].fn
                        ? {
                            ...common,
                            ...props.calcCellStyle,
                          }
                        : {
                            ...common,
                          }
                    }
                    parentColumnId={
                      props.uniqueKey
                        ? colOptions[props.uniqueKey]
                          ? colOptions[props.uniqueKey]
                          : colOptions['table_id']
                        : colOptions['table_id']
                    }
                    componentName="mutilTable"
                    editPropName={item}
                    isReadonly
                    value={
                      typeof colOptions[item] === 'object'
                        ? colOptions[item].value
                        : colOptions[item]
                    }
                  />
                );
              })();

              const editInput = (() => {
                return (
                  <MyInput
                    style={{ minWidth: '100px' }}
                    value={
                      typeof colOptions[item] === 'object'
                        ? colOptions[item].value
                        : colOptions[item]
                    }
                    parentColumnId={
                      props.uniqueKey
                        ? colOptions[props.uniqueKey]
                          ? colOptions[props.uniqueKey]
                          : colOptions['table_id']
                        : colOptions['table_id']
                    }
                    addStyle={
                      `td_id_${colOptions[props.uniqueKey]}_${item}_${idx}` !== curEditTdId.value
                        ? {
                            ...props.cellStyle,
                            borderTop: 'none',
                            borderBottom: 'none',
                            borderRight: 'none',
                            textAlign: 'center',
                            borderRadius: 0,
                          }
                        : {
                            textAlign: 'center',
                          }
                    }
                    editPropName={item}
                    componentName="mutilTable"
                  />
                );
              })();

              return bodyNotShowPropData.value.includes(item) ? null : (
                <td
                  id={`td_id_${colOptions[props.uniqueKey]}_${item}_${idx}`}
                  style={{
                    borderBottom: `1px solid ${props.tableBorderColor}`,
                    verticalAlign: 'middle',
                  }}
                  colspan="1"
                  rowspan={typeof colOptions[item] === 'object' ? colOptions[item].rowSpan : 1}
                  onClick={() =>
                    tdClickHandler(
                      `td_id_${colOptions[props.uniqueKey]}_${item}_${idx}`,
                      getIfHeaderItemCanEditByKey(item),
                    )
                  }
                >
                  {props.isReadOnly
                    ? isReadOnlySpan
                    : getIfHeaderItemCanEditByKey(item)
                    ? typeof colOptions[item] === 'object' && !colOptions[item].isCanEdit
                      ? isReadOnlySpan
                      : editInput
                    : isReadOnlySpan}
                </td>
              );
            })}
          </tr>
        );
      };

      const giveIdx2Item = (arr, parentSortId = '', classifyId = 0) => {
        return arr.map((v, idx) => {
          const item = {
            ...tools.deepCopy(v),
            sortIdx: '',
            classifyId: -1,
          };

          if (!item.sortIdx) {
            item.sortIdx = (parentSortId ? parentSortId + '_' : '') + idx;
          }
          item.classifyId = classifyId;

          if (item.children && item.children.length) {
            item.children = giveIdx2Item(Reflect.get(v, 'children'), item.sortIdx, classifyId + 1);
          }

          return item;
        });
      };

      // 以下省略...

      return {
        initData,
        renderPanelBody,
        // 以下省略...
      };
    },
    mounted() {
      event.on(`inputChange-mutilTable`, (val) => {
        tools.throttle(() => this.numberChangeHandler(val), 1000);
      });
    },
    watch: {
      tableHeader: {
        deep: true,
        handler(val) {
          this.initData();
        },
      },
    },
  };
</script>

<style scoped>
  .flexBox {
    display: flex;
    align-items: center;
    justify-content: center;
  }
</style>
